/**
 * 给定一个字符串，两类操作：
 * 1 p c: 将 Sp 改为 c
 * 2 a b: 问 S[a...b] 是否为回文串
 * 考虑快速判断回文串的方法，将 S[a...b] 看作是某进制的数，则正看和反看如果相等就是回文
 * 本质上这就是哈希，为了防止冲突，可以多使用几个进制，这里用了两个。
 * 为了方便观察，一个用了10，另一个用了质数。
 * 进制数本质上就是求和，因此可以使用线段树维护，对每一个区间的对每一个进制，
 * 维护 <正的和，反的和，本区间长度>
 * 则合并的时候，整个区间的数据分别为：
 * <左正和+右正和*进制^左长, 右反和+左反和*进制^右长, 左长+右长>
 * 其中进制的幂可以预处理出来
 */
#include <bits/stdc++.h>
using namespace std;

#include <bits/extc++.h>
using namespace __gnu_pbds;

using llt = unsigned long long;
using pii = pair<int, int>;
using vi = vector<int>;

int const SZ = 2;
const array<llt, SZ> HEX {10ULL, 29ULL};
vector<array<llt, SZ>> Hex;

void init(int n){
    Hex.clear(); Hex.reserve(n+7);
    Hex.push_back({1ULL, 1ULL});
    
    for(int i=1;i<n+7;++i){
        const auto & a = Hex[i - 1];
        array<llt, SZ> b;
        for(int j=0;j<SZ;++j){
            b[j] = a[j] * HEX[j];
        }
        Hex.push_back(b);
    }

    return;
}

string S;

struct SegTree{ // 线段树带延迟

using llt = unsigned long long;

using value_type = vector<array<llt, 3>>; // <从左到右的和, 从右到左的和, 数量级>
vector<value_type> data; // 线段树

using lazy_type = llt;
vector<lazy_type> lazy; // 延迟标记

/// 从下往上计算信息，要变动
value_type _up_(const value_type & ls, const value_type & rs) {
    value_type ans(HEX.size());
    for(int i=0,n=HEX.size();i<n;++i){
        auto & now = ans[i];
        const auto & left = ls[i];
        const auto & right = rs[i];
        now[0] = left[0] + right[0] * Hex[left[2]][i];
        now[1] = right[1] + left[1] * Hex[right[2]][i];
        now[2] = left[2] + right[2];
    }
    return ans;
}

/// 从上往下计算信息，要变动
void _dn_(int t, int s, int e, const lazy_type & delta) {
    assert(s == e);
    for(int i=0,n=HEX.size();i<n;++i){
        auto & now = data[t][i];
        now[0] = now[1] = delta;
        now[2] = 1;
    }
}

/// 初始化，清零，不用动
void init(int n) {
    data.assign(n + 1 << 2, value_zero());
    lazy.assign(n + 1 << 2, lazy_zero());
}

/// 这个函数不用动
void build(int n) {
    _build(1, 1, n);
}

/// 几乎不用动
value_type query(int t, int s, int e, int a, int b) {
    if(a <= s and e <= b) {
        return data[t];
    }
    _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    value_type ans = value_zero();
    if(a <= mid) ans = _up_(ans, query(lson(t), s, mid, a, b));
    if(mid < b) ans = _up_(ans, query(rson(t), mid + 1, e, a, b));
    return ans;
}

/// 几乎不用动
void modify(int t, int s, int e, int a, int b, const lazy_type & delta) {
    if(a <= s and e <= b) {
        _dn_(t, s, e, delta);
        return;
    }
    _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    if(a <= mid) modify(lson(t), s, mid, a, b, delta);
    if(mid < b) modify(rson(t), mid + 1, e, a, b, delta);
    _pushUp(t);
    return;
}

/// 这个函数不用动
void _pushUp(int t) {
    data[t] = _up_(data[lson(t)], data[rson(t)]);
}

/// 这个函数几乎不用动
void _pushDown(int t, int s, int e) {
    if(lazy_zero() == lazy[t]) return;
    auto & lz = lazy[t];
    auto ls = lson(t), rs = rson(t);
    int mid = (s + e) >> 1;

    _dn_(ls, s, mid, lz);
    _dn_(rs, mid + 1, e, lz);

    lz = lazy_zero();
}


/// 几乎不用动
void _build(int t, int s, int e) {
    if(s == e) {
        _dn_(t, s, e, S[s - 1] - 'a');
        return; 
    }
    int mid = (s + e) >> 1;
    _build(lson(t), s, mid);
    _build(rson(t), mid + 1, e);
    _pushUp(t);
}

/// 辅助函数，视延迟的类型而变动
static const lazy_type & lazy_zero() {
    static const lazy_type LAZY0 = 0;
    return LAZY0; 
}

/// 辅助函数，视线段树信息类型而变动
static const value_type & value_zero() {
    static const value_type VALUE0 = value_type(SZ, array<llt, 3>{0ULL, 0ULL, 0ULL});
    return VALUE0;
}

/// 这两个函数不用变动
static int lson(int x) {return x << 1;}
static int rson(int x) {return lson(x) | 1;}


}St;

int N, Q;

bool isOK(const SegTree::value_type & v){
    for(const auto & a : v){
        if(a[0] != a[1]) return false;
    }
    return true;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(0);
    cin >> N >> Q >> S;
    init(N);
    St.init(N); St.build(N);

    char ch;
    for(int op,a,b,q=1;q<=Q;++q){
        cin >> op >> a;
        if(1 == op){
            cin >> ch;
            St.modify(1, 1, N, a, a, ch - 'a');
        }else if(2 == op){
            cin >> b;
            auto ans = St.query(1, 1, N, a, b);
            puts(isOK(ans)?"Yes":"No");
        }else{
            assert(0);
        }
    }
    return 0;
}